#include "player_cache.hpp"
#include "logging.hpp"
#include <fstream>
#include <sstream>

namespace perf_boost {

const std::string PlayerCache::CACHE_FILE_NAME = "perf_boost.cache";

PlayerCache::PlayerCache() : cacheModified(false) {
}

PlayerCache::~PlayerCache() {
    if (cacheModified) {
        SaveToFile();
    }
}

bool PlayerCache::LoadFromFile() {
    std::ifstream file(CACHE_FILE_NAME);
    if (!file.is_open()) {
        return false;
    }

    nameToGuidMap.clear();
    std::string line;
    size_t loadedEntries = 0;

    while (std::getline(file, line)) {
        if (line.empty() || line[0] == '#') {
            continue;
        }

        size_t delimiterPos = line.find('=');
        if (delimiterPos == std::string::npos) {
            continue;
        }

        std::string playerName = line.substr(0, delimiterPos);
        std::string guidStr = line.substr(delimiterPos + 1);

        try {
            uint64_t guid = std::stoull(guidStr);
            nameToGuidMap[playerName] = guid;
            loadedEntries++;
        } catch (const std::exception&) {
            continue;
        }
    }

    file.close();
    cacheModified = false;
    
    if (loadedEntries > 0) {
        DEBUG_LOG("PlayerCache: Loaded " << loadedEntries << " player name->GUID mappings from cache");
    }

    return loadedEntries > 0;
}

bool PlayerCache::SaveToFile() {
    if (nameToGuidMap.empty()) {
        return true;
    }

    std::ofstream file(CACHE_FILE_NAME);
    if (!file.is_open()) {
        DEBUG_LOG("PlayerCache: Failed to open cache file for writing");
        return false;
    }

    file << "# perf_boost player name to GUID cache\n";
    file << "# Format: playername=guid\n";
    
    for (const auto& entry : nameToGuidMap) {
        file << entry.first << "=" << entry.second << "\n";
    }

    file.close();
    cacheModified = false;
    
    DEBUG_LOG("PlayerCache: Saved " << nameToGuidMap.size() << " player name->GUID mappings to cache");
    return true;
}

void PlayerCache::AddPlayerMapping(const char* playerName, uint64_t guid) {
    if (!playerName || guid == 0) {
        return;
    }

    std::string name(playerName);
    auto it = nameToGuidMap.find(name);
    
    if (it == nameToGuidMap.end() || it->second != guid) {
        nameToGuidMap[name] = guid;
        cacheModified = true;
        // Save immediately when new mapping is added
        SaveToFile();
    }
}

uint64_t PlayerCache::GetGuidForPlayer(const char* playerName) {
    if (!playerName) {
        return 0;
    }

    auto it = nameToGuidMap.find(std::string(playerName));
    return (it != nameToGuidMap.end()) ? it->second : 0;
}

bool PlayerCache::HasPlayerMapping(const char* playerName) {
    if (!playerName) {
        return false;
    }

    return nameToGuidMap.find(std::string(playerName)) != nameToGuidMap.end();
}

void PlayerCache::PopulateFromPlayerData(const std::vector<PlayerData>& players) {
    for (const auto& player : players) {
        if (player.resolved && player.guid != 0) {
            AddPlayerMapping(player.name, player.guid);
        }
    }
}

size_t PlayerCache::GetCacheSize() const {
    return nameToGuidMap.size();
}

void PlayerCache::Clear() {
    nameToGuidMap.clear();
    cacheModified = true;
}

}